#include"使用队列结构实现医院诊室看病流程模拟.h"

ReturnInformation Simulate()
{
	//准备病人信息
	srand((unsigned int)time(nullptr));
	int n = 0;
	cout << "请输入病人数量：";
	do
	{
		//n = 100;
		cin >> n;
		if(n < 0)
		{
			cout << "您的输入有误，请重新输入：" << endl;
		}
	}while(n < 0);
	shared_ptr<PatientInformation[]> sp(new PatientInformation[n]());//病人数据
	for(int i = 0; i < n; ++i)
	{
		sp[i].Print();
	}
	queue<PatientInformation> q;//队列
	//开始看病
	int patientwait = 0;//单个病人的等待时间
	int doctorwait = 0, npatientwait = 0;//医生的总等待时长与所有病人的总等待时长
	int nowtime = 8 * 60, finishtime = 12 * 60;//开始时间与结束时间（8~12点）
	double num = 0;//计算实际就诊人数
	//病人依次到
	int remaining = 0;//剩余时间
	//将在12点前到达的病人入队
	for(int i = 0; i < n && nowtime < finishtime; ++i)
	{
		//当前队列为空时：
		if(q.IsEmpty())
		{
			assert(sp[i]._arrive >= remaining);//由于感觉医生等待时间有些问题，所以设置了该断言
			nowtime += sp[i]._arrive - remaining;
			doctorwait += sp[i]._arrive - remaining;
			q.emplace(sp[i]);	
			remaining = q.Front()._treat;//将剩余时间更新为队首治疗时间
		}
		//当前队列不为空时：
		else
		{
			//当剩余时间remaining不够下一个病人到达时
			if(sp[i]._arrive > remaining)
			{
				nowtime += q.Front()._treat;//实际时间+=当前病人的治疗时间
				q.Pop();
				++num;
				while(!q.IsEmpty())
				{
					remaining += q.Front()._treat;
					nowtime += q.Front()._treat;
					q.Pop();
					++num;
					if(sp[i]._arrive <= remaining)
					{
						break;
					}
				}
			}
			//当剩余时间remaining足够下一个病人到达时，将新病人入队，并对时间做相应处理（注意，这里不要使用队列为空判断，
			//因为根据上述逻辑，可能出现队列为空时恰好可以允许新病人入队的情况
			if(remaining >= sp[i]._arrive)
			{
				q.emplace(sp[i]);	
				remaining -= sp[i]._arrive;//扣除部分剩余时间
				patientwait = patientwait - sp[i]._arrive + sp[i - 1]._treat;	
				npatientwait += patientwait;//将新入队病人的等待时间加到病人的总等待时间中
			}
			//若队列为空都无法让新病人入队，则进入下一次最外层for循环(需要注意，不要更新i，需要使用情况一处理新病人) 
			else
			{
				--i;
			}
		}
	}
	//处理病人全部入队，但时间尚未到达12点的特殊情况
	while(nowtime < finishtime)
	{
		if(!q.IsEmpty())
		{
			nowtime += q.Front()._treat;
			q.Pop();
			++num;
		}
		else
		{
			break;
		}
	}
	//cout << doctorwait << " " <<  npatientwait << " " << num << endl;
	return ReturnInformation((double)doctorwait, (double)npatientwait, (double)num);
}

ReturnInformation MultipleSimulations()
{
	double averdoctorwait = 0, avernpatientwait = 0, avernum = 0;
	int n = 10;
	assert(n);//n==0时进行断言，避免下面的求平均值时出现/0的低级错误
	for(int i = 0; i < n; ++i)
	{
		auto Information = Simulate();
		cout << "第" << i + 1 << "次模拟的结果如下：" << endl;
		cout << "医生等待时间： " << (int)Information._doctorwait << "min" << endl;
		cout << "病人总计等待时间： " << (int)Information._npatientwait << "min" << endl;
		cout << "就诊人数： " << (int)Information._num << endl << endl;
		averdoctorwait += Information._doctorwait;
		avernpatientwait += Information._npatientwait;
		avernum += Information._num;
	}
	return ReturnInformation(averdoctorwait / n, avernpatientwait / n, avernum / n);
}





//queue<int> q;
//q.Front();
//
//	for(int i = 0; i < n; ++i)
//	{
//		q.emplace(sp[i]);
//	}
//	while(!q.IsEmpty() || nowtime < finishtime)
//	{
//		nowtime += q.Front()._arrive;
//		doctorwait += q.Front()._arrive;
//		nowtime += q.Front()._treat;
//	}
